package axelrod;

import javax.swing.SwingUtilities;


public class Environment { 
    private int numOfAgents;
    private int numOfTurns;
    
    private AxelrodAgent[] agents;
    private int[] scores;
    
    private int firstMove;
    private int secondMove;
    private int lastFirstMove;
    private int lastSecondMove;
    private int firstAgent;
    private int secondAgent;
    
    public static final int MOVE_COOPERATE = 0;
    public static final int MOVE_DEFECT = 1;
    
    public static final String ALLD_AGENT = "ALLD";
    public static final String TIT_AGENT = "TIT";
    public static final String TES_AGENT = "TES";
    public static final String JOS_AGENT = "JOS";
    public static final String SPP_AGENT = "SPP";
    public static final String COP_AGENT = "COP";
    
    private UserInterface inter;
    
    private boolean finished;
    
    private final int[][] agentGain = {{3, 0}, {4, 1}};

    /** Creates the environment and agents with the GUI.
     * @param numOfAgents the number of agents.
     * @param numOfTurns the number of turns for each mach.
     * @param agents the types of agents.
     */
    public Environment(int numOfAgents, int numOfTurns, String[] agents, 
                       UserInterface inter) {
        //set the number of agents and turns per mathch
        this.numOfAgents = numOfAgents;
        this.numOfTurns = numOfTurns;
        //init the agent pool
        //create the scores and agents array
        scores = new int[numOfAgents];
        this.agents = new AxelrodAgent[numOfAgents];
        //add all agents
        for(int i = 0;i < agents.length;i++) {
            try {
              this.agents[i] = createAgent(agents[i]);
            } catch(NullPointerException e) {
              System.err.println(agents[i] + " is not a valid agent specifier");
            }
        }
        //init the agents for the first match
        firstAgent = 0;
        secondAgent = 1;
        this.inter = inter;
        this.finished = false;
    }
    
    /** Starts a match between the agents and automatically updates the agents
     * that are next to play.
     */
    public void startMatch() {
        if(finished) {
            return;
        }
        lastFirstMove = Environment.MOVE_DEFECT;
        lastSecondMove = Environment.MOVE_DEFECT;
        inter.updatePlaying(firstAgent, secondAgent);
        agents[firstAgent].startMatch();
        agents[secondAgent].startMatch();
        for(int i = 0;i < numOfTurns;i++) {
            //get the agent moves
            firstMove =  agents[firstAgent].getMove(i, lastSecondMove);
            secondMove = agents[secondAgent].getMove(i, lastFirstMove);
            //update current moves and score
            lastFirstMove = firstMove;
            lastSecondMove = secondMove;
            computeScores();
            //update the interface
            inter.updateActions(firstMove, secondMove, i);
        }
        inter.updateScores(firstAgent, secondAgent, scores[firstAgent], 
                           scores[secondAgent]);
        //update the agents for the next match
        if(secondAgent == agents.length - 1) {
            firstAgent ++;
            secondAgent = 1 + firstAgent; 
        } else {
            secondAgent++;
        }
        if(firstAgent == agents.length - 1) {
          finished = true;
          displayWinner();
        }
    }

    /** Runs the entire tournament at once.
     */
    public void startTournament() {
        if(finished) {
            return;
        }
        for(int i = 0;i < (agents.length - 1) * agents.length / 2;i++) {
            startMatch();
        }
    }
    
    private void computeScores() {
        scores[firstAgent]+= agentGain[firstMove][secondMove];
        scores[secondAgent]+= agentGain[secondMove][firstMove];
    }
    
    private AxelrodAgent createAgent(String agentName) {
        if(agentName.equals(ALLD_AGENT)) {
            return new ALLDAgent();
        }
        if(agentName.equals(TIT_AGENT)) {
            return new TITAgent();
        }
        if(agentName.equals(TES_AGENT)) {
            return new TESAgent();
        }
        if(agentName.equals(JOS_AGENT)) {
            return new JOSAgent();
        }
        if(agentName.equals(SPP_AGENT)) {
            return new SimplePAgent();
        }
        if(agentName.equals(COP_AGENT)) {
            return new CondPAgent();
        }
        return null;
    }

    private void displayWinner() {
        int max = 0;
        int result = -1;
        for(int i = 0;i < scores.length;i++) {
            if(max < scores[i]) {
                max = scores[i];
                result = i;
            }
        }
        inter.displayWinner(result);
    }
}
